package synchronization;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class IncrementorRaceCondition {

	public static void main(String[] args) throws InterruptedException {
		testCounter(new NaiveCouner(), 50, 10000);
		testCounter(new SynchonizedCouner(), 50, 10000);
		testCounter(new AtomicCouner(), 50, 10000);
	}

	private static void testCounter(final Counter counter, int threadsCount, final int repeats) throws InterruptedException {
		List<Thread> threads = new ArrayList<Thread>();
		for (int i = 0; i < threadsCount; i++) {
			Thread t = new Thread(new Runnable() {
				public void run() {
					for (int j = 0; j < repeats; j++) {
						counter.inc();
					}
				}
			});
			threads.add(t);
			t.start();
		}

		for (Thread t : threads) {
			t.join();
		}

		System.out.println(
			counter.getClass().getName() + ": " + 
			"expected=" + (threadsCount * repeats)	+ 
			", real=" + counter.get());
	}
}

interface Counter {
	public int inc();

	public int get();
}

class NaiveCouner implements Counter {
	private int i;

	public int get() {
		return i;
	}

	public int inc() {
		return ++i;
	}
}

class SynchonizedCouner implements Counter {
	private int i;

	public synchronized int get() {
		return i;
	}

	public synchronized int inc() {
		return ++i;
	}
}

class AtomicCouner implements Counter {
	private AtomicInteger i = new AtomicInteger();

	public synchronized int get() {
		return i.get();
	}

	public synchronized int inc() {
		return i.incrementAndGet();
	}
}
